import Vue from 'vue'
import store from '@/store/index'
import router from '@/router'
import { remote } from 'anov-core'

let wsInstance = null
let deviceNum = 0
/********************* setting **********************/
// 监听的 state 名字，系统内定
let CANDIDATE = [
  'faceRecognize',
  'gestureRecognize',
  'lightSensor',
  'voiceFeedback',
  'voiceRecognize',
  'theme',
  'language',
  'dataSource',
  'sound',
  'remote',
  'page',
  'cmlpanel',
  'focus'
]
/**
 * 状态观察器
 * @param {string} path state 路径
 */
function stateObserver(path) {
  store.watch(
    // state path
    (store) => store[path],
    // callback
    (value) => {
      let data = { [path]: value }
      // ws ready and app connected
      if (wsInstance?.ws?.readyState === 1 && deviceNum > 0) {
        wsInstance.sendInfo(data).catch((e) => console.log(e))
      }
    },
    // options
    { deep: true }
  )
}
/********************* setting **********************/

/********************* router **********************/

router.onReady(() => {
  // 路由信息
  const routeOption = router.options.routes
    .filter((route) => !!route.component && route.path !== '*')
    .filter((route) => route.remoteControl !== false)
    .map((item) => {
      return {
        path: item.path,
        name: item.name,
        nameText: item.nameText,
        model: item.model
      }
    })
  store.commit('remote/WS_ROUTE', { routeOption })
})
// 路由守卫
router.afterEach((to) => {
  const currentPath = to.path
  store.commit('remote/WS_ROUTE', { currentPath })
})
/********************* router **********************/

// export default remote

export default function init(config) {
  if (wsInstance) {
    console.warn('Already hava a Websocket instance')
    return
  }
  // websocket connection
  wsInstance = remote(config)
  if (!wsInstance) return
  Vue.prototype.$ws = wsInstance

  // 合并自定义的监听对象
  if (Array.isArray(wsInstance.config)) {
    CANDIDATE = CANDIDATE.concat(wsInstance.config)
  }
  for (let i = 0; i < CANDIDATE.length; i++) {
    stateObserver(CANDIDATE[i])
  }

  // 监听 message 消息
  wsInstance.addEventListener('message', (e, next) => {
    let res = e.data
    const isOpen = store.state.remote?.isOpen
    if (!res || !isOpen) return
    const { data, type } = res
    if (type === 'STATE') {
      // 更新state
      store.dispatch('remote/WS_EXCHANGE_DATA', data)
      next(true)
    } else if (type === 'ACTION') {
      const nextWatch = (data, next) => {
        let allEv = []
        const storeWatcher = (path) => {
          return new Promise((resolve, reject) => {
            const watchId = store.watch(
              // state path
              (store, getter) => {
                const keys = path.split('.')
                return keys.reduce((acc, current) => {
                  if ((acc !== undefined || acc !== null) && acc[current]) {
                    return acc[current]
                  } else {
                    return undefined
                  }
                }, store)
              },
              // callback
              (value) => {
                resolve(value)
                watchId()
              }
            )
            setTimeout(() => {
              reject()
            }, 5000)
          })
        }
        if (Array.isArray(data)) {
          for (let i = 0; i < data.length; i++) {
            if (data[i].stateId) {
              allEv.push(storeWatcher(data[i].stateId))
            }
          }
        } else {
          if (data.stateId) {
            allEv.push(storeWatcher(data.stateId))
          }
        }
        if (!allEv.length) {
          next({ success: true, data }) // added by WUYAX @2022-01-04
          return
        }
        Promise.all(allEv)
          .then(() => {
            next({ success: true, data })
          })
          .catch(() => {
            next({ success: false, data })
          })
      }
      // 监听store变化确定调用next
      nextWatch(data, next)
      // 触发action
      if (Array.isArray(data)) {
        for (let i = 0; i < data.length; i++) {
          const id = data[i].id
          const value = data[i].value
          app.actionServer.exec(id, value, false)
        }
      } else {
        const id = data.id
        const value = data.value
        app.actionServer.exec(id, value, false)
      }
    } else if (type === 'GET') {
      // 获取State的数据
      next({ success: true, ...store.getters['remote/WS_GET_DATA'](res.data) })
    }
  })

  // 监听系统消息
  wsInstance.addEventListener('sys', (res) => {
    const data = res.data.data
    if (data === 'quit') {
      deviceNum = 0
      wsInstance.close(4001, 'forced exit')
    } else if (data === 'disconnect') {
      deviceNum--
    } else if (data === 'connected') {
      deviceNum++
      // 发送初始化消息
      wsInstance.sendInfo({ candidate: CANDIDATE }).catch((e) => console.log(e))
    }
  })

  // 监听WS错误
  wsInstance.addEventListener('error', (err) => {
    const { message } = err
    if (message && message.indexOf('成功') > -1) {
      // 数据通信成功
      wsInstance.dispatchEvent('success')
      store.commit('env/setIsConnectCapacityServer', true)
    } else {
      store.commit('env/setIsConnectCapacityServer', false)
    }
    if (message && message.indexOf('重复') > -1) {
      // 重复连接错误码 4000 自定义 https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
      wsInstance.close(4000, 'duplicate connections')
    }
  })
}

/**
 * 连接websocket
 * @param {string} serverPath 服务器地址
 * @param {string} code 大屏连接码
 * @returns Promise
 */
export function connectWebsocket(serverPath, projectId, code) {
  if (!serverPath) return Promise.reject(`invalid serverPath!`)
  if (!code) return Promise.reject('invalid code, need a six-digit code.')
  if (!wsInstance)
    return Promise.reject(
      'You are in offline mode and cannot connect to the server.'
    )
  let baseUrl = serverPath
  baseUrl = baseUrl.replace(/^(http|https)/, 'ws')
  baseUrl = baseUrl.replace(/\/$|$/, '/api/v1/devs/pc/')
  // baseurl + projectId + 大屏code + 大屏code
  const WSURL = `${baseUrl}${projectId}/${code}/${code}`
  return wsInstance.connect(WSURL)
}
